import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 25397
 * Date: 2021-11-28
 * Time: 17:45
 */
class Money{
    public double m=12.5;
}
class Money2 implements  Cloneable{
    public double m=12.5;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable{
    public Money money=new Money();
    public Money2 money2=new Money2();
    public int age;
    public void eat(){
        System.out.println("正在吃东西");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
    //有接口要重写接口方法，但是你ctrl+左键进去Cloneable会发现，Cloneable接口里面什么也没有
   /* @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }*/


    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp=(Person) super.clone();
        tmp.money2=(Money2)this.money2.clone();  // 用Money2的时候使用
        return tmp;
    }

}
public class TestDemo {
    /*public static void main(String[] args) throws CloneNotSupportedException {//
        Person person=new Person();
        person.age=18;
        Person person1=(Person) person.clone();//clone方法返回的是Object类型，我们需要强转为Person
        //一个对象要克隆产生一个副本，则该引用指向的对象一定是可克隆的，所以我们的Person类那里要有一个Cloneable接口
        System.out.println(person1);//这里会直接跳到toString里面
        System.out.println("==============");
        person1.age=19;
        System.out.println(person);
        System.out.println(person1);

        //决定深拷贝和浅拷贝的，不是代码的用途，而是代码的实现
        //浅拷贝
        System.out.println(person.money.m);//详见String01,24分46秒处
        //Person类创建了对象person，person里面有的成员属性money，
        // money在堆上（包含在person里面，person在堆上），money指向一个Money类的对象（也在堆上）
        //可以通过money来调用它指向对象的成员属性m
        System.out.println(person1.money.m);//和上面一样打印12.5
        person.money.m=99.1;
        System.out.println(person1.money.m);//也打印99.1，因为拷贝出来的money也指向同一个对象

        //深拷贝
        //如果想money不被改变，你的money也必须被克隆，我们这里用Money2，防止前面代码被破坏
        System.out.println(person.money2.m);//12.5
        System.out.println(person1.money2.m);//12.5
        person.money2.m=100;
        System.out.println(person.money2.m);//100
        System.out.println(person1.money2.m);//12.5
    }*/


    /*public static void main(String[] args) {
        //字符串定义的三种方式
        //法一
        String str="abc";//直接赋值
        //法二
        String str2=new String("hello");//String本身是引用类型，你可以new一个对象
        //方法2是调用String的构造方法
        //法三
        char[]chars={'a','b','c'};
        String str3=new String(chars);//String构造方法可以把存储单个字符的字符数组转换成字符串
        System.out.println(str3);//打印abc
    }*/

    /*public static void main(String[] args) {
        String str="abc";
        String str2=str;//把str指向的对象地址给str2
        System.out.println(str);
        System.out.println(str2);
        str="bit";
        System.out.println("==============");
        System.out.println(str);//bit
        System.out.println(str2);//abc
        //为什么都指向一个对象，str修改了，对str2无效呢？
        //双引号""引起的属于字符串常量，常量是无法被修改的
        //那为什么str打印出来的是bit呢？
        //str="bit"是修改str的指向，不是修改“abc”的内容
    }*/


    /*public static void func(String s,char[]arr) {
        s="wxy";//将s的指向改变，不改变原先str的内容
        arr[0]='h';//改变了chars数组里的内容
    }
    public static void main(String[] args) {
        String str="abcdef";
        char[] chars={'b','i','t'};
        func(str,chars);
        System.out.println(str);//打印abcdef
        System.out.println(Arrays.toString(chars));//打印[h,i,t]
    }*/

    /*public static void main(String[] args) {
        String str1="hello";
        String str2=new String("hello");
        System.out.println(str1==str2);
        //str1是直接把hello地址给str1


        //1.class文件常量池:编译的时候产生的，比如int a=10;

        //2.运行时常量池：程序把编译好的字节码文件，加载到JVM中后，会生成一个运行时常量池（在方法区生成）
        //ps：运行时常量池是class文件常量池放到方法区生成的

        //3.字符串常量池，主要存放字符串常量->本质上是一个哈希表（StringTable）
        //ps：双引号引起来的字符串常量才会放到字符串常量池里面
        //ps:哈希表概念——是数据结构中描述和组织数据的一种方式


        //什么是池？
        //池的意义是提高效率用的，你用的时候不用再创建了，直接去池里面去取
        //代码示例如下
        String str3="abc";
        String str4="abc";//池里已经有一个abc字符串了，直接拿过来引用即可
        System.out.println(str3==str4);
    }*/


    /*public static void main(String[] args) {
        String str1="hello";
        String str2="he"+"llo";//此时“he”和“llo”都是常量，在编译时就已经确定好是hello，所以也会从池子里找出hello
        System.out.println(str1==str2);//true
        String str3="he";
        String str4=str3+"llo";//str3是一个变量，编译的时候无法知道是什么
        //“he"在常量池中，“llo”也在常量池中，他们拼接会产生一个新的对象（不在常量池中）
        System.out.println(str1==str4);//false
    }*/

    /*public static void main(String[] args) {
        String str1="11";
        String str2=new String("1")+new String("1");
        System.out.println(str1==str2);//false，详情内存解析见String（1） 2小时:04
    }*/

    /*public static void main(String[] args) {
        String str1="11";
        String str2=new String("1")+new String("1");
        str2.intern();//手动入池，当字符串常量池没有的时候，就会入池
        System.out.println(str1==str2);//这个是比较指向对象的地址
        System.out.println(str1.equals(str2));//这个是比较指向对象的内容
    }*/


    public static void main(String[] args){
        String s1="abc"+"def";//1
        String s2=new String(s1);//2
        if(s1.equals(s2))//3
            System.out.println(".equals succeeded");//4
        if(s1==s2)//5
            System.out.println("==succeeded");//6
    }//4执行，6不执行，如果s2=“abcdef”这种常量则会在字符串常量池里面找

}
